#coding=utf-8
import unreal
import os
import sys
import json
filepath = os.path.dirname(__file__)
sys.path.append(filepath)
import BaseFuncLib


# auto_ControlRig.py
@unreal.uclass()
class GLEditor(unreal.GlobalEditorUtilityBase):
    def __init__(self):
        super(GLEditor, self).__init__()



gl_editor = GLEditor()
sl_assets = gl_editor.get_selected_assets()

if(len(sl_assets) < 1):
    unreal.log_error("Nothing Selected!")
    sys.exit()

if(sl_assets[0].get_class().get_name() != "ControlRigBlueprint"):
    unreal.log_error("Selected is not ControlRigBlueprint!")
    sys.exit()

ctrlrig_bp = sl_assets[0]

# global graph_ctrl 
graph_ctrl = ctrlrig_bp.get_controller()

# global hierarchy_ctrl 
hierarchy_ctrl = ctrlrig_bp.get_hierarchy_controller()

# global hierarchy_info 
hierarchy_info = hierarchy_ctrl.get_hierarchy()

# global human_info
human_info = {}

# global node_lib
node_lib = {}

# global bone_key_dict
bone_key_dict = {}

# global ctrl_key_dict
ctrl_key_dict = {}

# global grp_key_dic
grp_key_dic = {}

# global node stack
node_stack = []

# global node stack branch
node_stack_branch = []

# global spine last
spine_last = ""
gl_pelvis = ""
gl_hand_r = ""
gl_hand_l = ""

# function library controller
func_lib = ctrlrig_bp.get_local_function_library()
func_lib_ctrl = ctrlrig_bp.get_controller(func_lib)



def initialize(settints_path, node_lib_path):
    # read settings
    global human_info
    with open(settints_path, "r") as file:
        file_content = file.read()
        human_info = json.loads(file_content)["HumanInfo"]

    # read node library
    global node_lib
    with open(node_lib_path, "r") as file:
        file_content = file.read()
        node_lib = json.loads(file_content)["NodeLib"]

    # set bone_key_dict
    global bone_key_dict
    all_bone_keys = hierarchy_info.get_bones()
    for bone_key in all_bone_keys:
        bone_key_dict[str(bone_key.name)] = bone_key

    # remove node
    all_node_key = graph_ctrl.get_graph().get_nodes()
    for node in all_node_key:
        graph_ctrl.remove_node(node)

    # remove ctrl
    all_ctrl_key = hierarchy_info.get_controls()
    for ctrl in all_ctrl_key:
        hierarchy_ctrl.remove_element(ctrl)

    # remove grp
    all_grp_key = hierarchy_info.get_nulls()
    for grp in all_grp_key:
        hierarchy_ctrl.remove_element(grp)

    # remove all funcs
    all_funcs = func_lib.get_functions()
    for func in all_funcs:
        func_lib_ctrl.remove_function_from_library(func.get_name())


def SettingRoot():
    root_info = human_info["root"]
    root_array = []
    for root_name in root_info:
        component_info = root_info[root_name]
        ctrl_key_dict[root_name] = BaseFuncLib.CreateEulerTransformCtrl(hierarchy_ctrl, hierarchy_info, component_info)

    # create grp
    grp_name = "Grp_IKFKCtrls"
    grp_key_dic[grp_name] = BaseFuncLib.CreateGrp(hierarchy_ctrl, hierarchy_info, grp_name, "")
    hierarchy_ctrl.add_parent(grp_key_dic[grp_name], ctrl_key_dict["root"])


def SettingBody():
    global spine_last
    global gl_pelvis

    body_info = human_info["body"]
    body_info_array = [bone for bone in body_info]
    spine_last = body_info_array[body_info["spine_count"]]
    gl_pelvis = body_info_array[0]
    body_info_array.pop()
    body_array = []
    index = 0
    for body_name in body_info_array:
        body_array.append(body_name)
        component_info = body_info[body_name]
        ctrl_key_dict[body_name] = BaseFuncLib.CreateEulerTransformCtrl(hierarchy_ctrl, hierarchy_info, component_info)

        BaseFuncLib.Set_Offset_Transform(hierarchy_info, ctrl_key_dict[body_name], bone_key_dict[body_name], component_info)

        if index > 0:
            BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict[body_array[index]], ctrl_key_dict[body_array[index-1]])
            hierarchy_ctrl.add_parent(ctrl_key_dict[body_array[index]], ctrl_key_dict[body_array[index-1]], weight=1, maintain_global_transform=False)

        index += 1

    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict[body_array[0]], ctrl_key_dict["root"])
    hierarchy_ctrl.add_parent(ctrl_key_dict[body_array[0]], ctrl_key_dict["root"], weight=1, maintain_global_transform=False)


def SettingLegFK():
    global gl_pelvis

    # setting LegFK R
    leg_fk_r_info = human_info["LegFK_R"]
    index = 0
    leg_fk_r_array = []
    for leg_fk_r_name in leg_fk_r_info:
        leg_fk_r_array.append(leg_fk_r_name)
        component_info = leg_fk_r_info[leg_fk_r_name]
        ctrl_key_dict[leg_fk_r_name] = BaseFuncLib.CreateEulerTransformCtrl(hierarchy_ctrl, hierarchy_info, component_info)

        BaseFuncLib.Set_Offset_Transform(hierarchy_info, ctrl_key_dict[leg_fk_r_name], bone_key_dict[leg_fk_r_name], component_info)

        if index > 0:
            BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict[leg_fk_r_array[index]], ctrl_key_dict[leg_fk_r_array[index-1]])
            hierarchy_ctrl.add_parent(ctrl_key_dict[leg_fk_r_array[index]], ctrl_key_dict[leg_fk_r_array[index-1]], weight=1, maintain_global_transform=False)
 
        index += 1

    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict[leg_fk_r_array[0]], ctrl_key_dict[gl_pelvis])
    hierarchy_ctrl.add_parent(ctrl_key_dict[leg_fk_r_array[0]], ctrl_key_dict[gl_pelvis], weight=1, maintain_global_transform=False)
    
    
    # setting LegFK L
    leg_fk_l_info = human_info["LegFK_L"]
    index = 0
    leg_fk_l_array = []
    for leg_fk_l_name in leg_fk_l_info:
        leg_fk_l_array.append(leg_fk_l_name)
        component_info = leg_fk_l_info[leg_fk_l_name]
        ctrl_key_dict[leg_fk_l_name] = BaseFuncLib.CreateEulerTransformCtrl(hierarchy_ctrl, hierarchy_info, component_info)

        BaseFuncLib.Set_Offset_Transform(hierarchy_info, ctrl_key_dict[leg_fk_l_name], bone_key_dict[leg_fk_l_name], component_info)

        if index > 0:
            BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict[leg_fk_l_array[index]], ctrl_key_dict[leg_fk_l_array[index-1]])
            hierarchy_ctrl.add_parent(ctrl_key_dict[leg_fk_l_array[index]], ctrl_key_dict[leg_fk_l_array[index-1]], weight=1, maintain_global_transform=False)

        index += 1

    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict[leg_fk_l_array[0]], ctrl_key_dict[gl_pelvis])
    hierarchy_ctrl.add_parent(ctrl_key_dict[leg_fk_l_array[0]], ctrl_key_dict[gl_pelvis], weight=1, maintain_global_transform=False)


    # setting leg ball r
    # create grp
    ball_r_info = human_info["Ball_R"]

    ball_r_array = []
    ball_name = [ball for ball in ball_r_info][0]

    grp_name = "Grp_ball_r"
    grp_key_dic[grp_name] = BaseFuncLib.CreateGrp(hierarchy_ctrl, hierarchy_info, grp_name, bone_key_dict[ball_name])

    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, grp_key_dic[grp_name], ctrl_key_dict["root"])
    hierarchy_ctrl.add_parent(grp_key_dic[grp_name], ctrl_key_dict["root"], weight=1, maintain_global_transform=False)

    # create ball ctrl
    component_info = ball_r_info[ball_name]
    ctrl_key_dict[ball_name] = BaseFuncLib.CreateEulerTransformCtrl(hierarchy_ctrl, hierarchy_info, component_info)

    BaseFuncLib.Set_Offset_Transform(hierarchy_info, ctrl_key_dict[ball_name], bone_key_dict[ball_name], component_info)

    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict[ball_name], grp_key_dic[grp_name])
    hierarchy_ctrl.add_parent(ctrl_key_dict[ball_name], grp_key_dic[grp_name], weight=1, maintain_global_transform=False)


    
    # setting leg ball l
    # create grp
    ball_l_info = human_info["Ball_L"]
 
    ball_l_array = []
    ball_name = [ball for ball in ball_l_info][0]

    grp_name = "Grp_ball_l"
    grp_key_dic[grp_name] = BaseFuncLib.CreateGrp(hierarchy_ctrl, hierarchy_info, grp_name, bone_key_dict[ball_name])

    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, grp_key_dic[grp_name], ctrl_key_dict["root"])
    hierarchy_ctrl.add_parent(grp_key_dic[grp_name], ctrl_key_dict["root"], weight=1, maintain_global_transform=False)

    # create ball ctrl
    component_info = ball_l_info[ball_name]
    ctrl_key_dict[ball_name] = BaseFuncLib.CreateEulerTransformCtrl(hierarchy_ctrl, hierarchy_info, component_info)

    BaseFuncLib.Set_Offset_Transform(hierarchy_info, ctrl_key_dict[ball_name], bone_key_dict[ball_name], component_info)

    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict[ball_name], grp_key_dic[grp_name])
    hierarchy_ctrl.add_parent(ctrl_key_dict[ball_name], grp_key_dic[grp_name], weight=1, maintain_global_transform=False)


def SettingArmFK():
    global gl_hand_r
    global gl_hand_l

    # setting ArmFK R
    arm_fk_r_info = human_info["ArmFK_R"]
    gl_hand_r = [bone for bone in arm_fk_r_info][-1]
    index = 0
    arm_fk_r_array = []
    for arm_fk_r_name in arm_fk_r_info:
        arm_fk_r_array.append(arm_fk_r_name)
        component_info = arm_fk_r_info[arm_fk_r_name]
        ctrl_key_dict[arm_fk_r_name] = BaseFuncLib.CreateEulerTransformCtrl(hierarchy_ctrl, hierarchy_info, component_info)

        BaseFuncLib.Set_Offset_Transform(hierarchy_info, ctrl_key_dict[arm_fk_r_name], bone_key_dict[arm_fk_r_name], component_info)

        if index > 0:
            BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict[arm_fk_r_array[index]], ctrl_key_dict[arm_fk_r_array[index-1]])
            hierarchy_ctrl.add_parent(ctrl_key_dict[arm_fk_r_array[index]], ctrl_key_dict[arm_fk_r_array[index-1]], weight=1, maintain_global_transform=False)

        index += 1

    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict[arm_fk_r_array[0]], ctrl_key_dict[spine_last])
    hierarchy_ctrl.add_parent(ctrl_key_dict[arm_fk_r_array[0]], ctrl_key_dict[spine_last], weight=1, maintain_global_transform=False)

    
    # setting ArmFK L
    arm_fk_l_info = human_info["ArmFK_L"]
    gl_hand_l = [bone for bone in arm_fk_l_info][-1]
    index = 0
    arm_fk_l_array = []
    for arm_fk_l_name in arm_fk_l_info:
        arm_fk_l_array.append(arm_fk_l_name)
        component_info = arm_fk_l_info[arm_fk_l_name]
        ctrl_key_dict[arm_fk_l_name] = BaseFuncLib.CreateEulerTransformCtrl(hierarchy_ctrl, hierarchy_info, component_info)

        BaseFuncLib.Set_Offset_Transform(hierarchy_info, ctrl_key_dict[arm_fk_l_name], bone_key_dict[arm_fk_l_name], component_info)

        if index > 0:
            BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict[arm_fk_l_array[index]], ctrl_key_dict[arm_fk_l_array[index-1]])
            hierarchy_ctrl.add_parent(ctrl_key_dict[arm_fk_l_array[index]], ctrl_key_dict[arm_fk_l_array[index-1]], weight=1, maintain_global_transform=False)

        index += 1

    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict[arm_fk_l_array[0]], ctrl_key_dict[spine_last])
    hierarchy_ctrl.add_parent(ctrl_key_dict[arm_fk_l_array[0]], ctrl_key_dict[spine_last], weight=1, maintain_global_transform=False)


def SettingFingers():
    global gl_hand_r
    global gl_hand_l

    # setting Fingers_R
    # create grp
    hand_r_key = ctrl_key_dict[gl_hand_r]
    grp_name = "Grp_Fingers_R"
    grp_key_dic[grp_name] = BaseFuncLib.CreateGrp(hierarchy_ctrl, hierarchy_info, grp_name, hand_r_key)
    hierarchy_ctrl.add_parent(grp_key_dic[grp_name], ctrl_key_dict["root"], weight=1, maintain_global_transform=False)

    #create fingers ctrl
    fingers_r_info = human_info["Fingers_R"]
    for fingers_r_name in fingers_r_info:
        fingers_r_array = []
        index = 0
        finger_part = fingers_r_info[fingers_r_name]
        for finger in finger_part:
            fingers_r_array.append(finger)
            component_info = finger_part[finger]
            ctrl_key_dict[finger] = BaseFuncLib.CreateEulerTransformCtrl(hierarchy_ctrl, hierarchy_info, component_info)

            BaseFuncLib.Set_Offset_Transform(hierarchy_info, ctrl_key_dict[finger], bone_key_dict[finger], component_info)

            if index > 0:
                BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict[fingers_r_array[index]], ctrl_key_dict[fingers_r_array[index-1]])
                hierarchy_ctrl.add_parent(ctrl_key_dict[fingers_r_array[index]], ctrl_key_dict[fingers_r_array[index-1]], weight=1, maintain_global_transform=False)

            index += 1

        BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict[fingers_r_array[0]], grp_key_dic[grp_name])
        hierarchy_ctrl.add_parent(ctrl_key_dict[fingers_r_array[0]], grp_key_dic[grp_name], weight=1, maintain_global_transform=False)


        
        
    # setting Fingers_L
    # create grp
    hand_l_key = ctrl_key_dict[gl_hand_l]
    grp_name = "Grp_Fingers_L"
    grp_key_dic[grp_name] = BaseFuncLib.CreateGrp(hierarchy_ctrl, hierarchy_info, grp_name, hand_l_key)
    hierarchy_ctrl.add_parent(grp_key_dic[grp_name], ctrl_key_dict["root"], weight=1, maintain_global_transform=False)

    #create fingers ctrl
    fingers_l_info = human_info["Fingers_L"]
    for fingers_l_name in fingers_l_info:
        fingers_l_array = []
        index = 0
        finger_part = fingers_l_info[fingers_l_name]
        for finger in finger_part:
            fingers_l_array.append(finger)
            component_info = finger_part[finger]
            ctrl_key_dict[finger] = BaseFuncLib.CreateEulerTransformCtrl(hierarchy_ctrl, hierarchy_info, component_info)

            BaseFuncLib.Set_Offset_Transform(hierarchy_info, ctrl_key_dict[finger], bone_key_dict[finger], component_info)

            if index > 0:
                BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict[fingers_l_array[index]], ctrl_key_dict[fingers_l_array[index-1]])
                hierarchy_ctrl.add_parent(ctrl_key_dict[fingers_l_array[index]], ctrl_key_dict[fingers_l_array[index-1]], weight=1, maintain_global_transform=False)

            index += 1

        BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict[fingers_l_array[0]], grp_key_dic[grp_name])
        hierarchy_ctrl.add_parent(ctrl_key_dict[fingers_l_array[0]], grp_key_dic[grp_name], weight=1, maintain_global_transform=False)


def SettingLegIK():
    # setting LegIK R
    # set leg ik
    leg_ik_r_info = human_info["LegIK_R"]

    leg_ik_r_array = []
    all_keys = list(leg_ik_r_info)

    thigh_name = all_keys[0]
    calf_name = all_keys[1]
    foot_name = all_keys[2]
    pole_name = all_keys[3]
    
    leg_ik_r_array.append(foot_name)
    component_info = leg_ik_r_info[foot_name]
    ctrl_key_dict["LegIK_R"] = BaseFuncLib.CreateEulerTransformCtrl(hierarchy_ctrl, hierarchy_info, component_info)

    BaseFuncLib.Set_Offset_Transform(hierarchy_info, ctrl_key_dict["LegIK_R"], bone_key_dict[foot_name], component_info)

    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict["LegIK_R"], grp_key_dic["Grp_IKFKCtrls"])
    hierarchy_ctrl.add_parent(ctrl_key_dict["LegIK_R"], grp_key_dic["Grp_IKFKCtrls"], weight=1, maintain_global_transform=False)
 
    #set pole
    component_info = leg_ik_r_info[pole_name]

    ctrl_key_dict["leg_pole_r"] = BaseFuncLib.CreatePoleCtrl(hierarchy_ctrl, hierarchy_info, component_info, 
                                                        bone_key_dict[thigh_name], bone_key_dict[calf_name], bone_key_dict[foot_name], 50)
    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict["leg_pole_r"], grp_key_dic["Grp_IKFKCtrls"])
    hierarchy_ctrl.add_parent(ctrl_key_dict["leg_pole_r"], grp_key_dic["Grp_IKFKCtrls"], weight=1, maintain_global_transform=False)

    
    # setting LegIK L
    # set leg ik
    leg_ik_l_info = human_info["LegIK_L"]

    leg_ik_l_array = []
    all_keys = list(leg_ik_l_info)

    thigh_name = all_keys[0]
    calf_name = all_keys[1]
    foot_name = all_keys[2]
    pole_name = all_keys[3]
    
    leg_ik_l_array.append(foot_name)
    component_info = leg_ik_l_info[foot_name]
    ctrl_key_dict["LegIK_L"] = BaseFuncLib.CreateEulerTransformCtrl(hierarchy_ctrl, hierarchy_info, component_info)

    BaseFuncLib.Set_Offset_Transform(hierarchy_info, ctrl_key_dict["LegIK_L"], bone_key_dict[foot_name], component_info)

    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict["LegIK_L"], grp_key_dic["Grp_IKFKCtrls"])
    hierarchy_ctrl.add_parent(ctrl_key_dict["LegIK_L"], grp_key_dic["Grp_IKFKCtrls"], weight=1, maintain_global_transform=False)

    #set pole
    component_info = leg_ik_l_info[pole_name]

    ctrl_key_dict["leg_pole_l"] = BaseFuncLib.CreatePoleCtrl(hierarchy_ctrl, hierarchy_info, component_info, 
                                                        bone_key_dict[thigh_name], bone_key_dict[calf_name], bone_key_dict[foot_name], 50)
    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict["leg_pole_l"], grp_key_dic["Grp_IKFKCtrls"])
    hierarchy_ctrl.add_parent(ctrl_key_dict["leg_pole_l"], grp_key_dic["Grp_IKFKCtrls"], weight=1, maintain_global_transform=False)

    # create ik fk switch control
    ctrl_name = "Leg_IKFK_Switch_R"
    ctrl_key_dict[ctrl_name] = BaseFuncLib.CreateBoolCtrl(hierarchy_ctrl, hierarchy_info, ctrl_name, True)
    hierarchy_ctrl.add_parent(ctrl_key_dict[ctrl_name], ctrl_key_dict["root"])

    ctrl_name = "Leg_IKFK_Switch_L"
    ctrl_key_dict[ctrl_name] = BaseFuncLib.CreateBoolCtrl(hierarchy_ctrl, hierarchy_info, ctrl_name, True)
    hierarchy_ctrl.add_parent(ctrl_key_dict[ctrl_name], ctrl_key_dict["root"])

    
def SettingArmIK():
    # setting ArmIK_R
    # set arm ik
    arm_ik_r_info = human_info["ArmIK_R"]

    arm_ik_r_array = []
    all_keys = list(arm_ik_r_info)

    upperarm_name = all_keys[0]
    lowerarm_name = all_keys[1]
    hand_name = all_keys[2]
    pole_name = all_keys[3]
    
    arm_ik_r_array.append(hand_name)
    component_info = arm_ik_r_info[hand_name]
    ctrl_key_dict["ArmIK_R"] = BaseFuncLib.CreateEulerTransformCtrl(hierarchy_ctrl, hierarchy_info, component_info)

    BaseFuncLib.Set_Offset_Transform(hierarchy_info, ctrl_key_dict["ArmIK_R"], bone_key_dict[hand_name], component_info)

    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict["ArmIK_R"], grp_key_dic["Grp_IKFKCtrls"])
    hierarchy_ctrl.add_parent(ctrl_key_dict["ArmIK_R"], grp_key_dic["Grp_IKFKCtrls"], weight=1, maintain_global_transform=False)


        
    #set pole
    component_info = arm_ik_r_info[pole_name]

    ctrl_key_dict["arm_pole_r"] = BaseFuncLib.CreatePoleCtrl(hierarchy_ctrl, hierarchy_info, component_info, 
                                                        bone_key_dict[upperarm_name], bone_key_dict[lowerarm_name], bone_key_dict[hand_name], 50)
    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict["arm_pole_r"], grp_key_dic["Grp_IKFKCtrls"])
    hierarchy_ctrl.add_parent(ctrl_key_dict["arm_pole_r"], grp_key_dic["Grp_IKFKCtrls"], weight=1, maintain_global_transform=False)
    
    
    
    
    # setting ArmIK_L
    # set arm ik
    arm_ik_l_info = human_info["ArmIK_L"]

    arm_ik_l_array = []
    all_keys = list(arm_ik_l_info)

    upperarm_name = all_keys[0]
    lowerarm_name = all_keys[1]
    hand_name = all_keys[2]
    pole_name = all_keys[3]
    
    arm_ik_l_array.append(hand_name)
    component_info = arm_ik_l_info[hand_name]
    ctrl_key_dict["ArmIK_L"] = BaseFuncLib.CreateEulerTransformCtrl(hierarchy_ctrl, hierarchy_info, component_info)

    BaseFuncLib.Set_Offset_Transform(hierarchy_info, ctrl_key_dict["ArmIK_L"], bone_key_dict[hand_name], component_info)

    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict["ArmIK_L"], grp_key_dic["Grp_IKFKCtrls"])
    hierarchy_ctrl.add_parent(ctrl_key_dict["ArmIK_L"], grp_key_dic["Grp_IKFKCtrls"], weight=1, maintain_global_transform=False)

        
    #set pole
    component_info = arm_ik_l_info[pole_name]

    ctrl_key_dict["arm_pole_l"] = BaseFuncLib.CreatePoleCtrl(hierarchy_ctrl, hierarchy_info, component_info, 
                                                        bone_key_dict[upperarm_name], bone_key_dict[lowerarm_name], bone_key_dict[hand_name], 50)
    BaseFuncLib.Set_Relative_Offset_Transform(hierarchy_info, ctrl_key_dict["arm_pole_l"], grp_key_dic["Grp_IKFKCtrls"])
    hierarchy_ctrl.add_parent(ctrl_key_dict["arm_pole_l"], grp_key_dic["Grp_IKFKCtrls"], weight=1, maintain_global_transform=False)

    # create ik fk switch control
    ctrl_name = "Arm_IKFK_Switch_R"
    ctrl_key_dict[ctrl_name] = BaseFuncLib.CreateBoolCtrl(hierarchy_ctrl, hierarchy_info, ctrl_name, True)
    hierarchy_ctrl.add_parent(ctrl_key_dict[ctrl_name], ctrl_key_dict["root"])

    ctrl_name = "Arm_IKFK_Switch_L"
    ctrl_key_dict[ctrl_name] = BaseFuncLib.CreateBoolCtrl(hierarchy_ctrl, hierarchy_info, ctrl_name, True)
    hierarchy_ctrl.add_parent(ctrl_key_dict[ctrl_name], ctrl_key_dict["root"])


def CreateFunc_SetIKPole():
    func_lib_ctrl.add_function_to_library("SetIKPole", True)
    func_ctrl = ctrlrig_bp.get_controller_by_name("SetIKPole")
    func_ctrl.add_exposed_pin("FirstPoint", unreal.RigVMPinDirection.INPUT, "Bool", "None", "False")
    func_ctrl.change_exposed_pin_type("FirstPoint", cpp_type="FVector", cpp_type_object_path="/Script/CoreUObject.Vector", setup_undo_redo=True)
    func_ctrl.add_exposed_pin("SecondPoint", unreal.RigVMPinDirection.INPUT, "Bool", "None", "False")
    func_ctrl.change_exposed_pin_type("SecondPoint", cpp_type="FVector", cpp_type_object_path="/Script/CoreUObject.Vector", setup_undo_redo=True)
    func_ctrl.add_exposed_pin("ThirdPoint", unreal.RigVMPinDirection.INPUT, "Bool", "None", "False")
    func_ctrl.change_exposed_pin_type("ThirdPoint", cpp_type="FVector", cpp_type_object_path="/Script/CoreUObject.Vector", setup_undo_redo=True)
    func_ctrl.add_exposed_pin("PoleCtrl", unreal.RigVMPinDirection.INPUT, "FName", "None", "False")
    func_ctrl.add_exposed_pin("DistanceScale", unreal.RigVMPinDirection.INPUT, "Bool", "None", "False")
    func_ctrl.change_exposed_pin_type("DistanceScale", cpp_type="Double", cpp_type_object_path="None", setup_undo_redo=True)
    func_lib_ctrl.set_pin_default_value("SetIKPole.DistanceScale", "50")

    # create node connect
    BaseFuncLib.CreateNode(func_ctrl, node_lib, "VectorSub", "second_sub_first")
    func_ctrl.set_node_position_by_name("second_sub_first", unreal.Vector2D(-40, 240))
    func_ctrl.add_link("Entry.SecondPoint", "second_sub_first.A")
    func_ctrl.add_link("Entry.FirstPoint", "second_sub_first.B")

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "VectorSub", "third_sub_first")
    func_ctrl.set_node_position_by_name("third_sub_first", unreal.Vector2D(-40, 384))
    func_ctrl.add_link("Entry.ThirdPoint", "third_sub_first.A")
    func_ctrl.add_link("Entry.FirstPoint", "third_sub_first.B")

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "VectorDot", "second_sub_first_dot_third_sub_first")
    func_ctrl.set_node_position_by_name("second_sub_first_dot_third_sub_first", unreal.Vector2D(137, 312))
    func_ctrl.add_link("second_sub_first.Result", "second_sub_first_dot_third_sub_first.A")
    func_ctrl.add_link("third_sub_first.Result", "second_sub_first_dot_third_sub_first.B")

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "VectorLength", "third_sub_first_length")
    func_ctrl.set_node_position_by_name("third_sub_first_length", unreal.Vector2D(144, 464))
    func_ctrl.add_link("third_sub_first.Result", "third_sub_first_length.Value")

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "FloatDiv", "second_sub_first_project_length")
    func_ctrl.set_node_position_by_name("second_sub_first_project_length", unreal.Vector2D(330, 372))
    func_ctrl.add_link("second_sub_first_dot_third_sub_first.Result", "second_sub_first_project_length.A")
    func_ctrl.add_link("third_sub_first_length.Result", "second_sub_first_project_length.B")

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "VectorUnit", "third_sub_first_unit")
    func_ctrl.set_node_position_by_name("third_sub_first_unit", unreal.Vector2D(-32, 592))
    func_ctrl.add_link("third_sub_first.Result", "third_sub_first_unit.Value")

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "VectorScale", "third_sub_first_unit_scale")
    func_ctrl.set_node_position_by_name("third_sub_first_unit_scale", unreal.Vector2D(508, 515))
    func_ctrl.add_link("third_sub_first_unit.Result", "third_sub_first_unit_scale.Value")
    func_ctrl.add_link("second_sub_first_project_length.Result", "third_sub_first_unit_scale.Factor")

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "VectorSub", "second_sub_first_sub_third_sub_first_unit_scale")
    func_ctrl.set_node_position_by_name("second_sub_first_sub_third_sub_first_unit_scale", unreal.Vector2D(528, 336))
    func_ctrl.add_link("second_sub_first.Result", "second_sub_first_sub_third_sub_first_unit_scale.A")
    func_ctrl.add_link("third_sub_first_unit_scale.Result", "second_sub_first_sub_third_sub_first_unit_scale.B")

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "VectorUnit", "second_sub_first_sub_third_sub_first_unit_scale_unit")
    func_ctrl.set_node_position_by_name("second_sub_first_sub_third_sub_first_unit_scale_unit", unreal.Vector2D(736, 352))
    func_ctrl.add_link("second_sub_first_sub_third_sub_first_unit_scale.Result", "second_sub_first_sub_third_sub_first_unit_scale_unit.Value")

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "VectorScale", "second_sub_first_sub_third_sub_first_unit_scale_unit_scale")
    func_ctrl.set_node_position_by_name("second_sub_first_sub_third_sub_first_unit_scale_unit_scale", unreal.Vector2D(736, 512))
    func_ctrl.add_link("second_sub_first_sub_third_sub_first_unit_scale_unit.Result", "second_sub_first_sub_third_sub_first_unit_scale_unit_scale.Value")
    func_ctrl.add_link("Entry.DistanceScale", "second_sub_first_sub_third_sub_first_unit_scale_unit_scale.Factor")

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "VectorAdd", "temp_vector")
    func_ctrl.set_node_position_by_name("temp_vector", unreal.Vector2D(912, 256))
    func_ctrl.add_link("Entry.FirstPoint", "temp_vector.A")
    func_ctrl.add_link("third_sub_first_unit_scale.Result", "temp_vector.B")

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "VectorAdd", "final_vector")
    func_ctrl.set_node_position_by_name("final_vector", unreal.Vector2D(1056, 400))
    func_ctrl.add_link("temp_vector.Result", "final_vector.A")
    func_ctrl.add_link("second_sub_first_sub_third_sub_first_unit_scale_unit_scale.Result", "final_vector.B")

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetTransform", "set_pole_ctrl")
    func_ctrl.set_pin_default_value("set_pole_ctrl.Item.Type", "Control")
    func_ctrl.add_link("Entry.PoleCtrl", "set_pole_ctrl.Item.Name")
    func_ctrl.add_link("final_vector.Result", "set_pole_ctrl.Transform.Translation")
    func_ctrl.set_node_position_by_name("set_pole_ctrl", unreal.Vector2D(1356, 400))
    
    BaseFuncLib.CreateNode(func_ctrl, node_lib, "Sequence", "SetIKPole_Sequence")
    func_ctrl.add_link("Entry.ExecuteContext", "SetIKPole_Sequence.ExecuteContext")
    func_ctrl.add_link("SetIKPole_Sequence.A", "set_pole_ctrl.ExecuteContext")
    func_ctrl.add_link("SetIKPole_Sequence.B", "Return.ExecuteContext")
    func_ctrl.set_node_position_by_name("SetIKPole_Sequence", unreal.Vector2D(16, -16))


def CreateFunc_SetIKFKSwitch():
    func_lib_ctrl.add_function_to_library("SetIKFKSwitch", True)
    func_ctrl = ctrlrig_bp.get_controller_by_name("SetIKFKSwitch")
    func_ctrl.add_exposed_pin("FKCtrl_A", unreal.RigVMPinDirection.INPUT, "FName", "None", "False")
    func_ctrl.add_exposed_pin("FKCtrl_B", unreal.RigVMPinDirection.INPUT, "FName", "None", "False")
    func_ctrl.add_exposed_pin("FKCtrl_C", unreal.RigVMPinDirection.INPUT, "FName", "None", "False")
    func_ctrl.add_exposed_pin("IKCtrl", unreal.RigVMPinDirection.INPUT, "FName", "None", "False")
    func_ctrl.add_exposed_pin("IKCtrl_instead", unreal.RigVMPinDirection.INPUT, "FName", "None", "False")
    func_ctrl.add_exposed_pin("PoleCtrl", unreal.RigVMPinDirection.INPUT, "FName", "None", "False")
    func_ctrl.add_exposed_pin("Bone_A", unreal.RigVMPinDirection.INPUT, "FName", "None", "False")
    func_ctrl.add_exposed_pin("Bone_B", unreal.RigVMPinDirection.INPUT, "FName", "None", "False")
    func_ctrl.add_exposed_pin("Bone_C", unreal.RigVMPinDirection.INPUT, "FName", "None", "False")
    func_ctrl.add_exposed_pin("Switch", unreal.RigVMPinDirection.INPUT, "bool", "None", "False")
    func_lib_ctrl.set_pin_default_value("SetIKFKSwitch.Switch", "True")
    func_ctrl.add_exposed_pin("PrimaryAxis", unreal.RigVMPinDirection.INPUT, "Bool", "None", "False")
    func_ctrl.change_exposed_pin_type("PrimaryAxis", cpp_type="FVector", cpp_type_object_path="/Script/CoreUObject.Vector", setup_undo_redo=True)
    func_ctrl.add_exposed_pin("SecondaryAxis", unreal.RigVMPinDirection.INPUT, "Bool", "None", "False")
    func_ctrl.change_exposed_pin_type("SecondaryAxis", cpp_type="FVector", cpp_type_object_path="/Script/CoreUObject.Vector", setup_undo_redo=True)
    func_ctrl.add_exposed_pin("PoleDistanceScale", unreal.RigVMPinDirection.INPUT, "double", "None", "False")
    func_lib_ctrl.set_pin_default_value("SetIKFKSwitch.PoleDistanceScale", "50")

    # Create node connect 
    BaseFuncLib.CreateNode(func_ctrl, node_lib, "Sequence", "func_Sequence")
    func_ctrl.add_link("Entry.ExecuteContext", "func_Sequence.ExecuteContext")
    func_ctrl.add_link("func_Sequence.B", "Return.ExecuteContext")
    func_ctrl.set_node_position_by_name("func_Sequence", unreal.Vector2D(16, 0))

    func_ctrl.add_branch_node(unreal.Vector2D(96, 336), node_name="ikfk_branch")
    func_ctrl.add_link("func_Sequence.A", "ikfk_branch.ExecuteContext")
    func_ctrl.add_link("Entry.Switch", "ikfk_branch.Condition")

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "BoolNot", "bool_not")
    func_ctrl.add_link("Entry.Switch", "bool_not.Value")
    func_ctrl.set_node_position_by_name("bool_not", unreal.Vector2D(96,496))
    
    # set ik ----------------------------------------------------------------------------------------
    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetControlVisibility", "vis_ik_1")
    func_ctrl.add_link("Entry.FKCtrl_A", "vis_ik_1.Item.Name")
    func_ctrl.add_link("ikfk_branch.True", "vis_ik_1.ExecuteContext")
    func_ctrl.add_link("bool_not.Result", "vis_ik_1.bVisible")
    func_ctrl.set_node_position_by_name("vis_ik_1", unreal.Vector2D(360,96))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetControlVisibility", "vis_ik_2")
    func_ctrl.add_link("Entry.FKCtrl_B", "vis_ik_2.Item.Name")
    func_ctrl.add_link("vis_ik_1.ExecuteContext", "vis_ik_2.ExecuteContext")
    func_ctrl.add_link("bool_not.Result", "vis_ik_2.bVisible")
    func_ctrl.set_node_position_by_name("vis_ik_2", unreal.Vector2D(660,96))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetControlVisibility", "vis_ik_3")
    func_ctrl.add_link("Entry.FKCtrl_C", "vis_ik_3.Item.Name")
    func_ctrl.add_link("vis_ik_2.ExecuteContext", "vis_ik_3.ExecuteContext")
    func_ctrl.add_link("bool_not.Result", "vis_ik_3.bVisible")
    func_ctrl.set_node_position_by_name("vis_ik_3", unreal.Vector2D(960,96))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetControlVisibility", "vis_ik_4")
    func_ctrl.add_link("Entry.IKCtrl", "vis_ik_4.Item.Name")
    func_ctrl.add_link("vis_ik_3.ExecuteContext", "vis_ik_4.ExecuteContext")
    func_ctrl.add_link("Entry.Switch", "vis_ik_4.bVisible")
    func_ctrl.set_node_position_by_name("vis_ik_4", unreal.Vector2D(1260,96))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetControlVisibility", "vis_ik_5")
    func_ctrl.add_link("Entry.PoleCtrl", "vis_ik_5.Item.Name")
    func_ctrl.add_link("vis_ik_4.ExecuteContext", "vis_ik_5.ExecuteContext")
    func_ctrl.add_link("Entry.Switch", "vis_ik_5.bVisible")
    func_ctrl.set_node_position_by_name("vis_ik_5", unreal.Vector2D(1560,96))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "GetTransform", "ik_ctrl")
    func_ctrl.set_pin_default_value("ik_ctrl.Item.Type", "Bone")
    func_ctrl.add_link("Entry.IKCtrl_instead", "ik_ctrl.Item.Name")
    func_ctrl.set_node_position_by_name("ik_ctrl", unreal.Vector2D(1904,416))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "GetTransform", "pole_ctrl")
    func_ctrl.set_pin_default_value("pole_ctrl.Item.Type", "Control")
    func_ctrl.add_link("Entry.PoleCtrl", "pole_ctrl.Item.Name")
    func_ctrl.set_node_position_by_name("pole_ctrl", unreal.Vector2D(1904,96))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "BasicIK", "ik_solver")
    func_ctrl.add_link("Entry.Bone_A", "ik_solver.ItemA.Name")
    func_ctrl.add_link("Entry.Bone_B", "ik_solver.ItemB.Name")
    func_ctrl.add_link("Entry.Bone_C", "ik_solver.EffectorItem.Name")
    func_ctrl.set_pin_default_value("ik_solver.PoleVectorKind", "Location")
    func_ctrl.add_link("Entry.PrimaryAxis", "ik_solver.PrimaryAxis")
    func_ctrl.add_link("Entry.SecondaryAxis", "ik_solver.SecondaryAxis")
    func_ctrl.add_link("vis_ik_5.ExecuteContext", "ik_solver.ExecuteContext")
    func_ctrl.add_link("ik_ctrl.Transform", "ik_solver.Effector")
    func_ctrl.add_link("pole_ctrl.Transform.Translation", "ik_solver.PoleVector")
    func_ctrl.set_node_position_by_name("ik_solver", unreal.Vector2D(2460,96))
 
    BaseFuncLib.CreateNode(func_ctrl, node_lib, "GetTransform", "ik_get_bone_1")
    func_ctrl.set_pin_default_value("ik_get_bone_1.Item.Type", "Bone")
    func_ctrl.add_link("Entry.Bone_A", "ik_get_bone_1.Item.Name")
    func_ctrl.set_node_position_by_name("ik_get_bone_1", unreal.Vector2D(2832,400))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetTransform", "ik_set_ctrl_1")
    func_ctrl.set_pin_default_value("ik_set_ctrl_1.Item.Type", "Control")
    func_ctrl.add_link("Entry.FKCtrl_A", "ik_set_ctrl_1.Item.Name")
    func_ctrl.add_link("ik_get_bone_1.Transform", "ik_set_ctrl_1.Transform")
    func_ctrl.add_link("ik_solver.ExecuteContext", "ik_set_ctrl_1.ExecuteContext")
    func_ctrl.set_node_position_by_name("ik_set_ctrl_1", unreal.Vector2D(2832,96))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "GetTransform", "ik_get_bone_2")
    func_ctrl.set_pin_default_value("ik_get_bone_2.Item.Type", "Bone")
    func_ctrl.add_link("Entry.Bone_B", "ik_get_bone_2.Item.Name")
    func_ctrl.set_node_position_by_name("ik_get_bone_2", unreal.Vector2D(3132,400))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetTransform", "ik_set_ctrl_2")
    func_ctrl.set_pin_default_value("ik_set_ctrl_2.Item.Type", "Control")
    func_ctrl.add_link("Entry.FKCtrl_B", "ik_set_ctrl_2.Item.Name")
    func_ctrl.add_link("ik_get_bone_2.Transform", "ik_set_ctrl_2.Transform")
    func_ctrl.add_link("ik_set_ctrl_1.ExecuteContext", "ik_set_ctrl_2.ExecuteContext")
    func_ctrl.set_node_position_by_name("ik_set_ctrl_2", unreal.Vector2D(3132,96))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "GetTransform", "ik_get_bone_3")
    func_ctrl.set_pin_default_value("ik_get_bone_3.Item.Type", "Bone")
    func_ctrl.add_link("Entry.Bone_C", "ik_get_bone_3.Item.Name")
    func_ctrl.set_node_position_by_name("ik_get_bone_3", unreal.Vector2D(3432,400))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetTransform", "ik_set_ctrl_3")
    func_ctrl.set_pin_default_value("ik_set_ctrl_3.Item.Type", "Control")
    func_ctrl.add_link("Entry.FKCtrl_C", "ik_set_ctrl_3.Item.Name")
    func_ctrl.add_link("ik_get_bone_3.Transform", "ik_set_ctrl_3.Transform")
    func_ctrl.add_link("ik_set_ctrl_2.ExecuteContext", "ik_set_ctrl_3.ExecuteContext")
    func_ctrl.set_node_position_by_name("ik_set_ctrl_3", unreal.Vector2D(3432,96))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "DrawLine", "draw_line")
    func_ctrl.add_link("pole_ctrl.Transform.Translation", "draw_line.A")
    func_ctrl.add_link("ik_get_bone_2.Transform.Translation", "draw_line.B")
    func_ctrl.add_link("ik_set_ctrl_3.ExecuteContext", "draw_line.ExecuteContext")
    func_ctrl.set_node_position_by_name("draw_line", unreal.Vector2D(3732,96))
 
    # set fk ----------------------------------------------------------------------------------------
    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetControlVisibility", "vis_fk_1")
    func_ctrl.add_link("Entry.FKCtrl_A", "vis_fk_1.Item.Name")
    func_ctrl.add_link("ikfk_branch.False", "vis_fk_1.ExecuteContext")
    func_ctrl.add_link("bool_not.Result", "vis_fk_1.bVisible")
    func_ctrl.set_node_position_by_name("vis_fk_1", unreal.Vector2D(352, 1150))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetControlVisibility", "vis_fk_2")
    func_ctrl.add_link("Entry.FKCtrl_B", "vis_fk_2.Item.Name")
    func_ctrl.add_link("vis_fk_1.ExecuteContext", "vis_fk_2.ExecuteContext")
    func_ctrl.add_link("bool_not.Result", "vis_fk_2.bVisible")
    func_ctrl.set_node_position_by_name("vis_fk_2", unreal.Vector2D(652,1150))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetControlVisibility", "vis_fk_3")
    func_ctrl.add_link("Entry.FKCtrl_C", "vis_fk_3.Item.Name")
    func_ctrl.add_link("vis_fk_2.ExecuteContext", "vis_fk_3.ExecuteContext")
    func_ctrl.add_link("bool_not.Result", "vis_fk_3.bVisible")
    func_ctrl.set_node_position_by_name("vis_fk_3", unreal.Vector2D(952,1150))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetControlVisibility", "vis_fk_4")
    func_ctrl.add_link("Entry.IKCtrl", "vis_fk_4.Item.Name")
    func_ctrl.add_link("vis_fk_3.ExecuteContext", "vis_fk_4.ExecuteContext")
    func_ctrl.add_link("Entry.Switch", "vis_fk_4.bVisible")
    func_ctrl.set_node_position_by_name("vis_fk_4", unreal.Vector2D(1252,1150))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetControlVisibility", "vis_fk_5")
    func_ctrl.add_link("Entry.PoleCtrl", "vis_fk_5.Item.Name")
    func_ctrl.add_link("vis_fk_4.ExecuteContext", "vis_fk_5.ExecuteContext")
    func_ctrl.add_link("Entry.Switch", "vis_fk_5.bVisible")
    func_ctrl.set_node_position_by_name("vis_fk_5", unreal.Vector2D(1552,1150))
  
    BaseFuncLib.CreateNode(func_ctrl, node_lib, "GetTransform", "fk_get_ctrl_1")
    func_ctrl.set_pin_default_value("fk_get_ctrl_1.Item.Type", "Control")
    func_ctrl.add_link("Entry.FKCtrl_A", "fk_get_ctrl_1.Item.Name")
    func_ctrl.set_node_position_by_name("fk_get_ctrl_1", unreal.Vector2D(1852,1450))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetTransform", "fk_set_bone_1")
    func_ctrl.set_pin_default_value("fk_set_bone_1.Item.Type", "Bone")
    func_ctrl.add_link("Entry.Bone_A", "fk_set_bone_1.Item.Name")
    func_ctrl.add_link("fk_get_ctrl_1.Transform", "fk_set_bone_1.Transform")
    func_ctrl.add_link("vis_fk_5.ExecuteContext", "fk_set_bone_1.ExecuteContext")
    func_ctrl.set_node_position_by_name("fk_set_bone_1", unreal.Vector2D(1852,1150))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "GetTransform", "fk_get_ctrl_2")
    func_ctrl.set_pin_default_value("fk_get_ctrl_2.Item.Type", "Control")
    func_ctrl.add_link("Entry.FKCtrl_B", "fk_get_ctrl_2.Item.Name")
    func_ctrl.set_node_position_by_name("fk_get_ctrl_2", unreal.Vector2D(2152,1450))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetTransform", "fk_set_bone_2")
    func_ctrl.set_pin_default_value("fk_set_bone_2.Item.Type", "Bone")
    func_ctrl.add_link("Entry.Bone_B", "fk_set_bone_2.Item.Name")
    func_ctrl.add_link("fk_get_ctrl_2.Transform", "fk_set_bone_2.Transform")
    func_ctrl.add_link("fk_set_bone_1.ExecuteContext", "fk_set_bone_2.ExecuteContext")
    func_ctrl.set_node_position_by_name("fk_set_bone_2", unreal.Vector2D(2152,1150))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "GetTransform", "fk_get_ctrl_3")
    func_ctrl.set_pin_default_value("fk_get_ctrl_3.Item.Type", "Control")
    func_ctrl.add_link("Entry.FKCtrl_C", "fk_get_ctrl_3.Item.Name")
    func_ctrl.set_node_position_by_name("fk_get_ctrl_3", unreal.Vector2D(2452,1450))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetTransform", "fk_set_bone_3")
    func_ctrl.set_pin_default_value("fk_set_bone_3.Item.Type", "Bone")
    func_ctrl.add_link("Entry.Bone_C", "fk_set_bone_3.Item.Name")
    func_ctrl.add_link("fk_get_ctrl_3.Transform", "fk_set_bone_3.Transform")
    func_ctrl.add_link("fk_set_bone_2.ExecuteContext", "fk_set_bone_3.ExecuteContext")
    func_ctrl.set_node_position_by_name("fk_set_bone_3", unreal.Vector2D(2452,1150))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "ParentConstraint", "ParentConstraint_ik_ctrl")
    func_ctrl.set_pin_default_value("ParentConstraint_ik_ctrl.Child.Type", "Control")
    func_ctrl.add_link("Entry.IKCtrl", "ParentConstraint_ik_ctrl.Child.Name")
    func_ctrl.set_pin_default_value("ParentConstraint_ik_ctrl.Parents.0.Item.Type", "Bone")
    func_ctrl.add_link("Entry.Bone_C", "ParentConstraint_ik_ctrl.Parents.0.Item.Name")
    func_ctrl.add_link("fk_set_bone_3.ExecuteContext", "ParentConstraint_ik_ctrl.ExecuteContext")
    func_ctrl.set_node_position_by_name("ParentConstraint_ik_ctrl", unreal.Vector2D(2752,1150))
    # ------------------------------
    func_ctrl.add_function_reference_node(func_lib.find_function("SetIKPole"), unreal.Vector2D(3380,1136))
    func_ctrl.add_link("ParentConstraint_ik_ctrl.ExecuteContext", "SetIKPole.ExecuteContext")

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "GetTransform", "fk_get_bone_1")
    func_ctrl.set_pin_default_value("fk_get_bone_1.Item.Type", "Bone")
    func_ctrl.add_link("Entry.Bone_A", "fk_get_bone_1.Item.Name")
    func_ctrl.set_node_position_by_name("fk_get_bone_1", unreal.Vector2D(3060,1450))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "GetTransform", "fk_get_bone_2")
    func_ctrl.set_pin_default_value("fk_get_bone_2.Item.Type", "Bone")
    func_ctrl.add_link("Entry.Bone_B", "fk_get_bone_2.Item.Name")
    func_ctrl.set_node_position_by_name("fk_get_bone_2", unreal.Vector2D(3060,1216))

    BaseFuncLib.CreateNode(func_ctrl, node_lib, "GetTransform", "fk_get_bone_3")
    func_ctrl.set_pin_default_value("fk_get_bone_3.Item.Type", "Bone")
    func_ctrl.add_link("Entry.Bone_C", "fk_get_bone_3.Item.Name")
    func_ctrl.set_node_position_by_name("fk_get_bone_3", unreal.Vector2D(3060,1000))

    func_ctrl.add_link("fk_get_bone_1.Transform.Translation", "SetIKPole.FirstPoint")
    func_ctrl.add_link("fk_get_bone_2.Transform.Translation", "SetIKPole.SecondPoint")
    func_ctrl.add_link("fk_get_bone_3.Transform.Translation", "SetIKPole.ThirdPoint")
    func_ctrl.add_link("Entry.PoleCtrl", "SetIKPole.PoleCtrl")
    func_ctrl.add_link("Entry.PoleDistanceScale", "SetIKPole.DistanceScale")


def CreateFunc_SetFingers():
    func_lib_ctrl.add_function_to_library("SetFingers", True)
    func_ctrl = ctrlrig_bp.get_controller_by_name("SetFingers")
    fingers_name = ["thumb_1", "thumb_2", "thumb_3", "index_1", "index_2", "index_3", "middle_1", "middle_2", "middle_3",
                    "ring_1", "ring_2", "ring_3", "pinky_1", "pinky_2", "pinky_3"]

    for finger in fingers_name:
        func_ctrl.add_exposed_pin(finger, unreal.RigVMPinDirection.INPUT, "FName", "None", "False")

    for finger in fingers_name:
        func_ctrl.add_exposed_pin(finger+"_ctrl", unreal.RigVMPinDirection.INPUT, "FName", "None", "False")

    # create node connect
    BaseFuncLib.CreateNode(func_ctrl, node_lib, "Sequence", "SetFingers_Sequence")
    func_ctrl.add_link("Entry.ExecuteContext", "SetFingers_Sequence.ExecuteContext")
    func_ctrl.add_link("SetFingers_Sequence.B", "Return.ExecuteContext")
    func_ctrl.set_node_position_by_name("SetFingers_Sequence", unreal.Vector2D(16, 0))

    index = 0
    node_stack = []
    for finger in fingers_name: 
        BaseFuncLib.CreateNode(func_ctrl, node_lib, "GetTransform", "get_"+finger)
        func_ctrl.set_pin_default_value("get_"+finger+".Item.Type", "Control")
        func_ctrl.add_link("Entry."+finger+"_ctrl", "get_"+finger+".Item.Name")
        func_ctrl.set_node_position_by_name("get_"+finger, unreal.Vector2D(208+index*300, 512))

        BaseFuncLib.CreateNode(func_ctrl, node_lib, "SetTransform", "set_"+finger)
        func_ctrl.set_pin_default_value("set_"+finger+".Item.Type", "Bone")
        func_ctrl.add_link("Entry."+finger, "set_"+finger+".Item.Name")
        func_ctrl.add_link("get_"+finger+".Transform", "set_"+finger+".Transform")
        func_ctrl.set_node_position_by_name("set_"+finger, unreal.Vector2D(208+index*300,256)) 
        if index < 1:
            func_ctrl.add_link("SetFingers_Sequence.A", "set_"+finger+".ExecuteContext")   
        else:
            func_ctrl.add_link(node_stack[-1]+".ExecuteContext", "set_"+finger+".ExecuteContext")
        node_stack.append("set_"+finger)
        index += 1


def CreateNodeConnect():
    # Begin
    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "ForwardsSolve", "Begin")
    node_stack.append("Begin")
    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "Sequence", "Sequence1")
    graph_ctrl.add_link(node_stack[-1]+".ExecuteContext", "Sequence1.ExecuteContext")
    graph_ctrl.set_node_position_by_name("Sequence1", unreal.Vector2D(300,0))
    node_stack_branch.append("Sequence1")


    # root
    root_info = human_info["root"]
    root_name = list(root_info)[0]
    component_info = root_info[root_name]
    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "ParentConstraint", root_name)
    graph_ctrl.set_pin_default_value(root_name+".Child.Type", "Bone")
    graph_ctrl.set_pin_default_value(root_name+".Child.Name", root_name)
    graph_ctrl.set_pin_default_value(root_name+".Parents.0.Item.Type", "Control")
    graph_ctrl.set_pin_default_value(root_name+".Parents.0.Item.Name", component_info[0])
    graph_ctrl.add_link(node_stack_branch[-1]+".A", root_name+".ExecuteContext")
    graph_ctrl.set_node_position_by_name(root_name, unreal.Vector2D(600,-1500))
    node_stack.append(root_name)

    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "ParentConstraint", "ParentConstraint_ikfk_grp")
    graph_ctrl.set_pin_default_value("ParentConstraint_ikfk_grp.Child.Type", "Null")
    graph_ctrl.set_pin_default_value("ParentConstraint_ikfk_grp.Child.Name", "Grp_IKFKCtrls")
    graph_ctrl.set_pin_default_value("ParentConstraint_ikfk_grp.Parents.0.Item.Type", "Control")
    graph_ctrl.set_pin_default_value("ParentConstraint_ikfk_grp.Parents.0.Item.Name", ctrl_key_dict["root"].name)
    graph_ctrl.add_link(root_name+".ExecuteContext", "ParentConstraint_ikfk_grp.ExecuteContext")
    graph_ctrl.set_node_position_by_name("ParentConstraint_ikfk_grp", unreal.Vector2D(900,-1500))
    node_stack.append("ParentConstraint_ikfk_grp")


    # body
    body_info = human_info["body"]
    body_info_array = list(body_info)
    body_info_array.pop()
    index = 1
    for body_name in body_info_array:
        component_info = body_info[body_name]
        BaseFuncLib.CreateNode(graph_ctrl, node_lib, "ParentConstraint", body_name)
        graph_ctrl.set_pin_default_value(body_name+".Child.Type", "Bone")
        graph_ctrl.set_pin_default_value(body_name+".Child.Name", body_name)
        graph_ctrl.set_pin_default_value(body_name+".Parents.0.Item.Type", "Control")
        graph_ctrl.set_pin_default_value(body_name+".Parents.0.Item.Name", component_info[0])
        graph_ctrl.add_link(node_stack[-1]+".ExecuteContext", body_name+".ExecuteContext")
        graph_ctrl.set_node_position_by_name(body_name, unreal.Vector2D(900+300*index,-1500))
        index += 1
        node_stack.append(body_name)


    # arm r---------------------------------------------------------------------------------
    fk_info = human_info["ArmFK_R"]
    fk_info_array = list(fk_info)
    ik_info = human_info["ArmIK_R"]
    ik_info_array = list(ik_info)

    # clavicle r
    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "GetTransform", "get_clavicle_ctrl_r")
    graph_ctrl.set_pin_default_value("get_clavicle_ctrl_r.Item.Type", "Control")
    graph_ctrl.set_pin_default_value("get_clavicle_ctrl_r.Item.Name", fk_info[fk_info_array[0]][0])
    graph_ctrl.set_node_position_by_name("get_clavicle_ctrl_r", unreal.Vector2D(992, -544))

    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "SetTransform", "set_clavicle_bone_r")
    graph_ctrl.set_pin_default_value("set_clavicle_bone_r.Item.Type", "Bone")
    graph_ctrl.set_pin_default_value("set_clavicle_bone_r.Item.Name", fk_info_array[0])
    graph_ctrl.add_link("get_clavicle_ctrl_r.Transform", "set_clavicle_bone_r.Transform")
    graph_ctrl.add_link("Sequence1.B", "set_clavicle_bone_r.ExecuteContext")
    graph_ctrl.set_node_position_by_name("set_clavicle_bone_r", unreal.Vector2D(992, -816))

    # duplicate bone
    cpy_bone_key = hierarchy_ctrl.duplicate_elements([bone_key_dict[fk_info_array[3]]])[0]
    hierarchy_ctrl.add_parent(cpy_bone_key, bone_key_dict["root"])
    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "ParentConstraint", "ParentConstraint_hand_r_cpy")
    graph_ctrl.set_pin_default_value("ParentConstraint_hand_r_cpy"+".Child.Type", "Bone")
    graph_ctrl.set_pin_default_value("ParentConstraint_hand_r_cpy"+".Child.Name", cpy_bone_key.name)
    graph_ctrl.set_pin_default_value("ParentConstraint_hand_r_cpy"+".Parents.0.Item.Type", "Control")
    graph_ctrl.set_pin_default_value("ParentConstraint_hand_r_cpy"+".Parents.0.Item.Name", ik_info[ik_info_array[2]][0])
    graph_ctrl.add_link("set_clavicle_bone_r.ExecuteContext", "ParentConstraint_hand_r_cpy.ExecuteContext")
    graph_ctrl.set_node_position_by_name("ParentConstraint_hand_r_cpy", unreal.Vector2D(1392, -816))

    graph_ctrl.add_function_reference_node(func_lib.find_function("SetIKFKSwitch"), unreal.Vector2D(1776, -832), "SetIKFKSwitch_arm_r")
    graph_ctrl.add_link("ParentConstraint_hand_r_cpy.ExecuteContext", "SetIKFKSwitch_arm_r.ExecuteContext")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_r.FKCtrl_A", fk_info[fk_info_array[1]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_r.FKCtrl_B", fk_info[fk_info_array[2]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_r.FKCtrl_C", fk_info[fk_info_array[3]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_r.IKCtrl", ik_info[ik_info_array[2]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_r.IKCtrl_instead", cpy_bone_key.name)
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_r.PoleCtrl", ik_info[ik_info_array[3]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_r.Bone_A", fk_info_array[1])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_r.Bone_B", fk_info_array[2])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_r.Bone_C", fk_info_array[3])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_r.PrimaryAxis.X", "1")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_r.PrimaryAxis.Y", "0")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_r.PrimaryAxis.Z", "0")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_r.SecondaryAxis.X", "0")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_r.SecondaryAxis.Y", "1")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_r.SecondaryAxis.Z", "0")

    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "GetControlBool", "ikfk_switch_arm_r")
    graph_ctrl.set_pin_default_value("ikfk_switch_arm_r.Control", "Arm_IKFK_Switch_R")
    graph_ctrl.add_link("ikfk_switch_arm_r.BoolValue", "SetIKFKSwitch_arm_r.Switch")
    graph_ctrl.set_node_position_by_name("ikfk_switch_arm_r", unreal.Vector2D(1456, -528))

    # Fingers R------------------------------------------------
    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "ParentConstraint", "ParentConstraint_ringers_grp_r")
    graph_ctrl.set_pin_default_value("ParentConstraint_ringers_grp_r"+".Child.Type", "Null")
    graph_ctrl.set_pin_default_value("ParentConstraint_ringers_grp_r"+".Child.Name", "Grp_Fingers_R")
    graph_ctrl.set_pin_default_value("ParentConstraint_ringers_grp_r"+".Parents.0.Item.Type", "Bone")
    graph_ctrl.set_pin_default_value("ParentConstraint_ringers_grp_r"+".Parents.0.Item.Name", fk_info_array[3])
    graph_ctrl.add_link("SetIKFKSwitch_arm_r.ExecuteContext", "ParentConstraint_ringers_grp_r"+".ExecuteContext")
    graph_ctrl.set_node_position_by_name("ParentConstraint_ringers_grp_r", unreal.Vector2D(2096,-816))

    fingers_info = human_info["Fingers_R"]
    fingers_info_array = list(fingers_info)
    fingers_name = []
    fingers_ctrl_name = []
    for fingers in fingers_info_array:
        temp_array = list(fingers_info[fingers])
        temp_info = fingers_info[fingers]
        for finger in temp_array:
            fingers_name.append(finger)
            fingers_ctrl_name.append(temp_info[finger][0])

    graph_ctrl.add_function_reference_node(func_lib.find_function("SetFingers"), unreal.Vector2D(2480, -832), "SetFingers_r")
    fingers_pin_name = ["thumb_1", "thumb_2", "thumb_3", "index_1", "index_2", "index_3", "middle_1", "middle_2", "middle_3",
                    "ring_1", "ring_2", "ring_3", "pinky_1", "pinky_2", "pinky_3"]
    for index in range(0, len(fingers_pin_name), 1):
        graph_ctrl.set_pin_default_value("SetFingers_r."+fingers_pin_name[index] , fingers_name[index])
        graph_ctrl.set_pin_default_value("SetFingers_r."+fingers_pin_name[index]+"_ctrl" , fingers_ctrl_name[index])

    graph_ctrl.add_link("ParentConstraint_ringers_grp_r.ExecuteContext", "SetFingers_r.ExecuteContext")


    # arm l---------------------------------------------------------------------------------
    fk_info = human_info["ArmFK_L"]
    fk_info_array = list(fk_info)
    ik_info = human_info["ArmIK_L"]
    ik_info_array = list(ik_info)

    # clavicle l
    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "GetTransform", "get_clavicle_ctrl_l")
    graph_ctrl.set_pin_default_value("get_clavicle_ctrl_l.Item.Type", "Control")
    graph_ctrl.set_pin_default_value("get_clavicle_ctrl_l.Item.Name", fk_info[fk_info_array[0]][0])
    graph_ctrl.set_node_position_by_name("get_clavicle_ctrl_l", unreal.Vector2D(992, 144))

    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "SetTransform", "set_clavicle_bone_l")
    graph_ctrl.set_pin_default_value("set_clavicle_bone_l.Item.Type", "Bone")
    graph_ctrl.set_pin_default_value("set_clavicle_bone_l.Item.Name", fk_info_array[0])
    graph_ctrl.add_link("get_clavicle_ctrl_l.Transform", "set_clavicle_bone_l.Transform")
    graph_ctrl.add_link("Sequence1.C", "set_clavicle_bone_l.ExecuteContext")
    graph_ctrl.set_node_position_by_name("set_clavicle_bone_l", unreal.Vector2D(992, -144))

    # duplicate bone
    cpy_bone_key = hierarchy_ctrl.duplicate_elements([bone_key_dict[fk_info_array[3]]])[0]
    hierarchy_ctrl.add_parent(cpy_bone_key, bone_key_dict["root"])
    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "ParentConstraint", "ParentConstraint_hand_l_cpy")
    graph_ctrl.set_pin_default_value("ParentConstraint_hand_l_cpy"+".Child.Type", "Bone")
    graph_ctrl.set_pin_default_value("ParentConstraint_hand_l_cpy"+".Child.Name", cpy_bone_key.name)
    graph_ctrl.set_pin_default_value("ParentConstraint_hand_l_cpy"+".Parents.0.Item.Type", "Control")
    graph_ctrl.set_pin_default_value("ParentConstraint_hand_l_cpy"+".Parents.0.Item.Name", ik_info[ik_info_array[2]][0])
    graph_ctrl.add_link("set_clavicle_bone_l.ExecuteContext", "ParentConstraint_hand_l_cpy.ExecuteContext")
    graph_ctrl.set_node_position_by_name("ParentConstraint_hand_l_cpy", unreal.Vector2D(1392, -144))

    graph_ctrl.add_function_reference_node(func_lib.find_function("SetIKFKSwitch"), unreal.Vector2D(1776, -160), "SetIKFKSwitch_arm_l")
    graph_ctrl.add_link("ParentConstraint_hand_l_cpy.ExecuteContext", "SetIKFKSwitch_arm_l.ExecuteContext")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_l.FKCtrl_A", fk_info[fk_info_array[1]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_l.FKCtrl_B", fk_info[fk_info_array[2]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_l.FKCtrl_C", fk_info[fk_info_array[3]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_l.IKCtrl", ik_info[ik_info_array[2]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_l.IKCtrl_instead", cpy_bone_key.name)
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_l.PoleCtrl", ik_info[ik_info_array[3]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_l.Bone_A", fk_info_array[1])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_l.Bone_B", fk_info_array[2])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_l.Bone_C", fk_info_array[3])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_l.PrimaryAxis.X", "-1")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_l.PrimaryAxis.Y", "0")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_l.PrimaryAxis.Z", "0")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_l.SecondaryAxis.X", "0")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_l.SecondaryAxis.Y", "-1")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_arm_l.SecondaryAxis.Z", "0")

    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "GetControlBool", "ikfk_switch_arm_l")
    graph_ctrl.set_pin_default_value("ikfk_switch_arm_l.Control", "Arm_IKFK_Switch_L")
    graph_ctrl.add_link("ikfk_switch_arm_l.BoolValue", "SetIKFKSwitch_arm_l.Switch")
    graph_ctrl.set_node_position_by_name("ikfk_switch_arm_l", unreal.Vector2D(1440, 160))

    # Fingers L------------------------------------------------
    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "ParentConstraint", "ParentConstraint_ringers_grp_l")
    graph_ctrl.set_pin_default_value("ParentConstraint_ringers_grp_l"+".Child.Type", "Null")
    graph_ctrl.set_pin_default_value("ParentConstraint_ringers_grp_l"+".Child.Name", "Grp_Fingers_L")
    graph_ctrl.set_pin_default_value("ParentConstraint_ringers_grp_l"+".Parents.0.Item.Type", "Bone")
    graph_ctrl.set_pin_default_value("ParentConstraint_ringers_grp_l"+".Parents.0.Item.Name", fk_info_array[3])
    graph_ctrl.add_link("SetIKFKSwitch_arm_l.ExecuteContext", "ParentConstraint_ringers_grp_l"+".ExecuteContext")
    graph_ctrl.set_node_position_by_name("ParentConstraint_ringers_grp_l", unreal.Vector2D(2096,-144))

    fingers_info = human_info["Fingers_L"]
    fingers_info_array = list(fingers_info)
    fingers_name = []
    fingers_ctrl_name = []
    for fingers in fingers_info_array:
        temp_array = list(fingers_info[fingers])
        temp_info = fingers_info[fingers]
        for finger in temp_array:
            fingers_name.append(finger)
            fingers_ctrl_name.append(temp_info[finger][0])

    graph_ctrl.add_function_reference_node(func_lib.find_function("SetFingers"), unreal.Vector2D(2785, -160), "SetFingers_l")
    fingers_pin_name = ["thumb_1", "thumb_2", "thumb_3", "index_1", "index_2", "index_3", "middle_1", "middle_2", "middle_3",
                    "ring_1", "ring_2", "ring_3", "pinky_1", "pinky_2", "pinky_3"]
    for index in range(0, len(fingers_pin_name), 1):
        graph_ctrl.set_pin_default_value("SetFingers_l."+fingers_pin_name[index] , fingers_name[index])
        graph_ctrl.set_pin_default_value("SetFingers_l."+fingers_pin_name[index]+"_ctrl" , fingers_ctrl_name[index])

    graph_ctrl.add_link("ParentConstraint_ringers_grp_l.ExecuteContext", "SetFingers_l.ExecuteContext")

    # Sequence
    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "Sequence", "Sequence2")
    graph_ctrl.add_link("Sequence1.D", "Sequence2.ExecuteContext")
    graph_ctrl.set_node_position_by_name("Sequence2", unreal.Vector2D(576, 896))

    # leg r---------------------------------------------------------------------------------
    fk_info = human_info["LegFK_R"]
    fk_info_array = list(fk_info)
    ik_info = human_info["LegIK_R"]
    ik_info_array = list(ik_info)

    # duplicate bone
    cpy_bone_key = hierarchy_ctrl.duplicate_elements([bone_key_dict[fk_info_array[2]]])[0]
    hierarchy_ctrl.add_parent(cpy_bone_key, bone_key_dict["root"])
    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "ParentConstraint", "ParentConstraint_foot_r_cpy")
    graph_ctrl.set_pin_default_value("ParentConstraint_foot_r_cpy"+".Child.Type", "Bone")
    graph_ctrl.set_pin_default_value("ParentConstraint_foot_r_cpy"+".Child.Name", cpy_bone_key.name)
    graph_ctrl.set_pin_default_value("ParentConstraint_foot_r_cpy"+".Parents.0.Item.Type", "Control")
    graph_ctrl.set_pin_default_value("ParentConstraint_foot_r_cpy"+".Parents.0.Item.Name", ik_info[ik_info_array[2]][0])
    graph_ctrl.add_link("Sequence2.A", "ParentConstraint_foot_r_cpy.ExecuteContext")
    graph_ctrl.set_node_position_by_name("ParentConstraint_foot_r_cpy", unreal.Vector2D(992, 550))

    graph_ctrl.add_function_reference_node(func_lib.find_function("SetIKFKSwitch"), unreal.Vector2D(1424, 528), "SetIKFKSwitch_leg_r")
    graph_ctrl.add_link("ParentConstraint_foot_r_cpy.ExecuteContext", "SetIKFKSwitch_leg_r.ExecuteContext")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_r.FKCtrl_A", fk_info[fk_info_array[0]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_r.FKCtrl_B", fk_info[fk_info_array[1]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_r.FKCtrl_C", fk_info[fk_info_array[2]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_r.IKCtrl", ik_info[ik_info_array[2]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_r.IKCtrl_instead", cpy_bone_key.name)
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_r.PoleCtrl", ik_info[ik_info_array[3]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_r.Bone_A", fk_info_array[0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_r.Bone_B", fk_info_array[1])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_r.Bone_C", fk_info_array[2])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_r.PrimaryAxis.X", "1")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_r.PrimaryAxis.Y", "0")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_r.PrimaryAxis.Z", "0")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_r.SecondaryAxis.X", "0")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_r.SecondaryAxis.Y", "-1")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_r.SecondaryAxis.Z", "0")

    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "GetControlBool", "ikfk_switch_leg_r")
    graph_ctrl.set_pin_default_value("ikfk_switch_leg_r.Control", "Leg_IKFK_Switch_R")
    graph_ctrl.add_link("ikfk_switch_leg_r.BoolValue", "SetIKFKSwitch_leg_r.Switch")
    graph_ctrl.set_node_position_by_name("ikfk_switch_leg_r", unreal.Vector2D(1088, 850))

    # ball r---------------------------------
    ball_info = human_info["Ball_R"]
    ball_info_array = list(ball_info)

    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "ParentConstraint", "ParentConstraint_ball_grp_r")
    graph_ctrl.set_pin_default_value("ParentConstraint_ball_grp_r"+".Child.Type", "Null")
    graph_ctrl.set_pin_default_value("ParentConstraint_ball_grp_r"+".Child.Name", "Grp_ball_r")
    graph_ctrl.set_pin_default_value("ParentConstraint_ball_grp_r"+".Parents.0.Item.Type", "Bone")
    graph_ctrl.set_pin_default_value("ParentConstraint_ball_grp_r"+".Parents.0.Item.Name", fk_info_array[2])
    graph_ctrl.add_link("SetIKFKSwitch_leg_r.ExecuteContext", "ParentConstraint_ball_grp_r.ExecuteContext")
    graph_ctrl.set_node_position_by_name("ParentConstraint_ball_grp_r", unreal.Vector2D(1792, 544))

    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "ParentConstraint", "ParentConstraint_ball_r")
    graph_ctrl.set_pin_default_value("ParentConstraint_ball_r"+".Child.Type", "Bone")
    graph_ctrl.set_pin_default_value("ParentConstraint_ball_r"+".Child.Name", ball_info_array[0])
    graph_ctrl.set_pin_default_value("ParentConstraint_ball_r"+".Parents.0.Item.Type", "Control")
    graph_ctrl.set_pin_default_value("ParentConstraint_ball_r"+".Parents.0.Item.Name", ball_info[ball_info_array[0]][0])
    graph_ctrl.add_link("ParentConstraint_ball_grp_r.ExecuteContext", "ParentConstraint_ball_r.ExecuteContext")
    graph_ctrl.set_node_position_by_name("ParentConstraint_ball_r", unreal.Vector2D(2208, 544))


    # leg l---------------------------------------------------------------------------------
    fk_info = human_info["LegFK_L"]
    fk_info_array = list(fk_info)
    ik_info = human_info["LegIK_L"]
    ik_info_array = list(ik_info)

    # duplicate bone
    cpy_bone_key = hierarchy_ctrl.duplicate_elements([bone_key_dict[fk_info_array[2]]])[0]
    hierarchy_ctrl.add_parent(cpy_bone_key, bone_key_dict["root"])
    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "ParentConstraint", "ParentConstraint_foot_l_cpy")
    graph_ctrl.set_pin_default_value("ParentConstraint_foot_l_cpy"+".Child.Type", "Bone")
    graph_ctrl.set_pin_default_value("ParentConstraint_foot_l_cpy"+".Child.Name", cpy_bone_key.name)
    graph_ctrl.set_pin_default_value("ParentConstraint_foot_l_cpy"+".Parents.0.Item.Type", "Control")
    graph_ctrl.set_pin_default_value("ParentConstraint_foot_l_cpy"+".Parents.0.Item.Name", ik_info[ik_info_array[2]][0])
    graph_ctrl.add_link("Sequence2.B", "ParentConstraint_foot_l_cpy.ExecuteContext")
    graph_ctrl.set_node_position_by_name("ParentConstraint_foot_l_cpy", unreal.Vector2D(992, 1050))

    graph_ctrl.add_function_reference_node(func_lib.find_function("SetIKFKSwitch"), unreal.Vector2D(1424, 1028), "SetIKFKSwitch_leg_l")
    graph_ctrl.add_link("ParentConstraint_foot_l_cpy.ExecuteContext", "SetIKFKSwitch_leg_l.ExecuteContext")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_l.FKCtrl_A", fk_info[fk_info_array[0]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_l.FKCtrl_B", fk_info[fk_info_array[1]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_l.FKCtrl_C", fk_info[fk_info_array[2]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_l.IKCtrl", ik_info[ik_info_array[2]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_l.IKCtrl_instead", cpy_bone_key.name)
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_l.PoleCtrl", ik_info[ik_info_array[3]][0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_l.Bone_A", fk_info_array[0])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_l.Bone_B", fk_info_array[1])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_l.Bone_C", fk_info_array[2])
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_l.PrimaryAxis.X", "-1")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_l.PrimaryAxis.Y", "0")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_l.PrimaryAxis.Z", "0")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_l.SecondaryAxis.X", "0")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_l.SecondaryAxis.Y", "1")
    graph_ctrl.set_pin_default_value("SetIKFKSwitch_leg_l.SecondaryAxis.Z", "0")

    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "GetControlBool", "ikfk_switch_leg_l")
    graph_ctrl.set_pin_default_value("ikfk_switch_leg_l.Control", "Leg_IKFK_Switch_L")
    graph_ctrl.add_link("ikfk_switch_leg_l.BoolValue", "SetIKFKSwitch_leg_l.Switch")
    graph_ctrl.set_node_position_by_name("ikfk_switch_leg_l", unreal.Vector2D(1088, 1350))

    # ball l---------------------------------
    ball_info = human_info["Ball_L"]
    ball_info_array = list(ball_info)

    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "ParentConstraint", "ParentConstraint_ball_grp_l")
    graph_ctrl.set_pin_default_value("ParentConstraint_ball_grp_l"+".Child.Type", "Null")
    graph_ctrl.set_pin_default_value("ParentConstraint_ball_grp_l"+".Child.Name", "Grp_ball_l")
    graph_ctrl.set_pin_default_value("ParentConstraint_ball_grp_l"+".Parents.0.Item.Type", "Bone")
    graph_ctrl.set_pin_default_value("ParentConstraint_ball_grp_l"+".Parents.0.Item.Name", fk_info_array[2])
    graph_ctrl.add_link("SetIKFKSwitch_leg_l.ExecuteContext", "ParentConstraint_ball_grp_l.ExecuteContext")
    graph_ctrl.set_node_position_by_name("ParentConstraint_ball_grp_l", unreal.Vector2D(1792, 1040))

    BaseFuncLib.CreateNode(graph_ctrl, node_lib, "ParentConstraint", "ParentConstraint_ball_l")
    graph_ctrl.set_pin_default_value("ParentConstraint_ball_l"+".Child.Type", "Bone")
    graph_ctrl.set_pin_default_value("ParentConstraint_ball_l"+".Child.Name", ball_info_array[0])
    graph_ctrl.set_pin_default_value("ParentConstraint_ball_l"+".Parents.0.Item.Type", "Control")
    graph_ctrl.set_pin_default_value("ParentConstraint_ball_l"+".Parents.0.Item.Name", ball_info[ball_info_array[0]][0])
    graph_ctrl.add_link("ParentConstraint_ball_grp_l.ExecuteContext", "ParentConstraint_ball_l.ExecuteContext")
    graph_ctrl.set_node_position_by_name("ParentConstraint_ball_l", unreal.Vector2D(2208, 1040))


def main(settints_path, node_lib_path):
    global graph_ctrl
    global hierarchy_ctrl
    global hierarchy_info
    global human_info
    global node_lib
    global bone_key_dict
    global ctrl_key_dict
    global grp_key_dic
    global node_stack
    global node_stack_branch
    global spine_last
    global func_lib
    global func_lib_ctrl
    global ctrlrig_bp

    # initialize
    initialize(settints_path, node_lib_path)

    # place controls
    # setting root
    SettingRoot()
    # setting body
    SettingBody()
    # setting leg fk
    SettingLegFK()
    # setting arm fK
    SettingArmFK()
    # setting fingers
    SettingFingers()
    # setting leg ik
    SettingLegIK()
    # setting arm ik
    SettingArmIK()

    # Create Custom Function
    CreateFunc_SetIKPole()
    CreateFunc_SetIKFKSwitch()
    CreateFunc_SetFingers()
    # create node connect
    CreateNodeConnect()


if __name__ == "__main__":
    settints_path = os.path.join(filepath, "RigSettings.json")
    node_lib_path = os.path.join(filepath, "NodeLib.json")
    main(settints_path, node_lib_path)
